/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "zlang_in.h"

int InterpretExpression_ReturnFunctionStack( struct ZlangRuntime *rt , struct ZlangInterpretStatementSegmentContext *interp_stat_seg_ctx )
{
	int					out_param_count ;
	int					out_param_index ;
	struct ZlangTokenDataUnitHeader		*token_info1 = NULL ;
	char					*token1 = NULL ;
	struct ZlangTokenDataUnitHeader		*token_info2 = NULL ;
	char					*token2 = NULL ;
	struct ZlangObject			*obj = NULL ;
	struct ZlangInterpretStatementContext	retval_interp_stat_ctx ;
	struct ZlangObject			*result_obj = NULL ;
	
	int					nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	TEST_RUNTIME_DEBUG( rt )
	{
		struct ZlangObjectsStackFrame *local_objs_stack_frame = GetCurrentLocalObjectsStackFrame( rt ) ;
		PRINT_TABS_AND_FORMAT( rt , "current stack : [%d][%s]-[%d][%d][%d][%d]" , rt->local_objs_stack_frame_array_curridx,local_objs_stack_frame->full_func_name , local_objs_stack_frame->stack_bottom,local_objs_stack_frame->stack_in_params_top,local_objs_stack_frame->stack_out_params_top,local_objs_stack_frame->stack_local_var_top )
	}
	
	out_param_count = GetOutputParameterCountInLocalObjectStack( rt ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "GetOutputParameterCountInLocalObjectStack out_param_count[%d]" , out_param_count )
	
	PEEKTOKEN_AND_SAVEINFO( rt , token_info1 , token1 )
	if( token_info1->token_type == TOKEN_TYPE_END_OF_STATEMENT )
	{
		out_param_index = 0 ;
		
		if( out_param_count != 0 )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "out_param_index[%d] != out_param_count[%d]" , out_param_index , out_param_count )
			
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_FUNC_PARAMETERS_COUNT_NOT_MATCHED , "return objs too little" )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_FUNC_PARAMETERS_COUNT_NOT_MATCHED;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "out_param_index[%d] == out_param_count[%d]" , out_param_index , out_param_count )
		}
	}
	else
	{
		for( out_param_index = 1 ; out_param_index <= out_param_count ; out_param_index++ )
		{
			if( out_param_index != 1 )
			{
				TRAVELTOKEN_AND_SAVEINFO( rt , token_info2 , token2 )
				if( token_info2->token_type != TOKEN_TYPE_PART_OF_STATEMENT )
				{
					SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect ','" )
					TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
					return ZLANG_ERROR_SYNTAX;
				}
			}
			
			TEST_RUNTIME_DEBUG( rt )
			{
				TOKENTYPE_TO_STRING( rt->travel_token_info->token_type , _zlang_token_type_str )
				PRINT_TABS_AND_FORMAT( rt , "CALL InterpretExpression , last_token[%s][%s]" , _zlang_token_type_str , rt->travel_token )
			}
			memset( & retval_interp_stat_ctx , 0x00 , sizeof(struct ZlangInterpretStatementContext) );
			retval_interp_stat_ctx.token_of_expression_end1 = TOKEN_TYPE_PART_OF_STATEMENT ;
			retval_interp_stat_ctx.token_of_expression_end2 = TOKEN_TYPE_END_OF_STATEMENT ;
			result_obj = NULL ;
			nret = InterpretExpression( rt , interp_stat_seg_ctx , & retval_interp_stat_ctx , & result_obj ) ;
			TEST_RUNTIME_DEBUG( rt )
			{
				TOKENTYPE_TO_STRING( rt->travel_token_info->token_type , _zlang_token_type_str )
				TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "InterpretExpression return[%d] last_token[%s][%s] " , nret , _zlang_token_type_str , rt->travel_token ); DebugPrintObject(rt,result_obj); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
			}
			if( nret == ZLANG_INFO_END_OF_EXPRESSION )
			{
				if( result_obj == NULL )
				{
					SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect expression" )
					TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
					return ZLANG_ERROR_SYNTAX;
				}
				NEXTTOKEN( rt )
			}
			else
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return nret;
			}
			
			token_info2 = rt->travel_token_info ;
			
			obj = GetOutputParameterInLocalObjectStack( rt , out_param_index ) ;
			if( obj == NULL )
			{
				SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_FUNC_PARAMETERS_COUNT_NOT_MATCHED , "too much return objects" )
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_ERROR_FUNC_PARAMETERS_COUNT_NOT_MATCHED;
			}
			
			nret = ReferObject( rt , obj , result_obj ) ;
			if( nret )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "ReferObject failed[%d]" , nret )
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_ERROR_GET_DATA_PTR;
			}
			
			TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "set out param " ); DebugPrintObject( rt , obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
			
			if( token_info2->token_type == TOKEN_TYPE_END_OF_STATEMENT )
				break;
		}
		
		if( out_param_index != out_param_count )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "out_param_index[%d] != out_param_count[%d]" , out_param_index , out_param_count )
			
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_FUNC_PARAMETERS_COUNT_NOT_MATCHED , "too little return objects" )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_FUNC_PARAMETERS_COUNT_NOT_MATCHED;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "out_param_index[%d] == out_param_count[%d]" , out_param_index , out_param_count )
		}
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	
	return ZLANG_INFO_RETURN;
}

